#ifndef MYTINYSTL_STACK_H_
#define MYTINYSTL_STACK_H_

// 这个头文件包含了一个模板类 stack
// stack : 栈

#include "deque.h"

namespace mystl
{
    // 模板类 stack
    // 模板参数一代表数据类型，参数二代表底层容器类型，缺省则使用 mystl::deque 作为底层容器
    template <class T, class Container = mystl::deque<T>>
    class stack
    {
    public:
        typedef Container container_type;
        // 使用底层容器的类型
        typedef typename Container::value_type          value_type;
        typedef typename Container::size_type           size_type;
        typedef typename Container::reference           reference;
        typedef typename Container::const_reference     const_reference;

        static_assert(std::is_same<T, value_type>::value,
                        "the value_type of Container should be same with T");
    
    private:
        container_type c_;      // 用底层容器表现 stack
    
    public:
        // 复制、构造、移动函数
        stack() = default;

        explicit stack(size_type n) : c_(n) { }

        stack(size_type n, const value_type& value) : c_(n, value) { }

        template <class Iter>
        stack(Iter first, Iter last) : c_(first, last) { }

        stack(std::initializer_list<T> ilist) : c_(ilist.begin(), ilist.end()) { }

        stack(const Container& c) : c_(c) { }

        stack(Container&& c) noexcept(std::is_nothrow_move_constructible<Container>::value)
            : c_(mystl::move(c)) { }
        
        stack(const stack& rhs) : c_(rhs.c_) { }

        stack(stack&& rhs) noexcept(std::is_nothrow_move_constructible<Container>::value)
            : c_(mystl::move(rhs.c_)) { }
        
        stack& operator=(const stack& rhs)
        {
            c_ = rhs.c_;
            return *this;
        }

        stack& operator=(stack&& rhs) noexcept(std::is_nothrow_move_constructible<Container>::value)
        {
            c_ = mystl::move(rhs.c_);
            return *this;
        }

        stack& operator=(std::initializer_list<T> ilist)
        {
            c_ = ilist;
            return *this;
        }

        ~stack() = default;

        // 访问元素相关操作
        reference top() {return c_.back(); }
        const_reference top() const { return c_.back(); }

        // 容量相关操作
        bool  empty() const noexcept { return c_.empty(); }
        size_type size() const noexcept { return c_.size(); }

        // 修改容器相关操作
        template <class ...Args>
        void emplace(Args&& ...args)
        {
            c_.emplace_back(mystl::forward<Args>(args)...);
        }

        void push(const value_type& value)
        {
            c_.push_back(value);
        }
        void push(value_type&& value)
        {
            c_.push_back(mystl::move(value));
        }

        void pop()
        {
            c_.pop_back();
        }

        void clear()
        {
            while (!empty())
                pop();
        }

        void swap(stack& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_)))
        {
            mystl::swap(c_, rhs.c_);
        }
    
    public:
        friend bool operator==(const stack& lhs, const stack& rhs) { return lhs.c_ == rhs.c_; }
        friend bool operator<(const stack& lhs, const stack& rhs) { return lhs.c_ < rhs.c_; }
    };

    // 重载比较操作符
    template <class T, class Container>
    bool operator==(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
    {
        return lhs == rhs;
    }

    template <class T, class Container>
    bool operator<(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
    {
        return lhs < rhs;
    }

    template <class T, class Container>
    bool operator!=(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
    {
        return !(lhs == rhs);
    }

    template <class T, class Container>
    bool operator>(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
    {
        return rhs < lhs;
    }

    template <class T, class Container>
    bool operator<=(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
    {
        return !(rhs > lhs);
    }

    template <class T, class Container>
    bool operator>=(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
    {
        return !(lhs < rhs);
    }

    // 重载 mystl 的 swap
    template <class T, class Container>
    void swap(const stack<T, Container>& lhs, const stack<T, Container>& rhs) noexcept(noexcept(lhs.swap(rhs)))
    {
        lhs.swap(rhs);
    }
}

#endif